package org.hackystat.devcathlon.engine.project;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.user.UserManager;
import org.hackystat.devcathlon.engine.db.util.HibernateUtil;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.configuration.jaxb.DevcathlonConfiguration;
import org.hackystat.sensorbase.client.SensorBaseClient;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;

/**
 * A thread-safe singleton class that manages access to the Projects in this system.
 * @author Anthony Du
 *
 */
public class ProjectManager {
  /** The singleton instance of this class. */
  private static ProjectManager theInstance = new ProjectManager();
  
  /** The private constructor. */
  private ProjectManager() {
    // does nothing at this point; will initialize from database later.
  }
  
  /**
   * Returns the singleton instance of the ProjectManager.
   * @return The ProjectManager.
   */
  public static ProjectManager getInstance() {
    return ProjectManager.theInstance;
  }
  
  /**
   * Adds a new project to the system.
   * @param name The project name.
   * @param owner The project owner.
   * @return The project.
   */
  public synchronized TeamProject addProject(String name, String owner) {
    // Attempt to get an existing project
    TeamProject project = getTeamProject(name);
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      project = new TeamProject(name, owner);
      session.save(project);
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return project;
  }
  
  /**
   * Adds a new team project to the system.
   * @param team The team.
   * @param name The project name.
   * @param owner The project owner.
   * @return The team project.
   */
  public synchronized TeamProject addProject(Team team, String name, String owner) {
    // Attempt to get an existing team project
    TeamProject teamProject = getTeamProject(name);
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    try {
      session.beginTransaction();
      if (null == teamProject) {
        teamProject = new TeamProject(name, owner);
        team.setTeamProject(teamProject);
        team.setProjectName(name);
        session.update(team);
        session.save(teamProject);
        System.out.println("Created Team Project: " + teamProject.getName());
      }
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return teamProject;
  }
  
  /**
   * Gets an existing team project from the system.
   * @param name The project name.
   * @return The team project.
   */
  public synchronized TeamProject getTeamProject(String name) {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    String hqlSelect = "from TeamProject p where p.name = :name";
    TeamProject teamProject = null;
    
    try {
      session.beginTransaction();
      Query query = session.createQuery(hqlSelect).setString("name", name);
      query.setMaxResults(1);
      teamProject = (TeamProject) query.uniqueResult();
      session.getTransaction().commit();
    }
    catch (HibernateException ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      throw ex;
    }
    return teamProject;
  }
  
  /**
   * Gets an existing project from the system.
   * @param name The project name.
   * @param owner The project owner's email.
   * @return The project.
   */
  public synchronized Project getProject(String name, String owner) {
    ConfigurationManager manager = ConfigurationManager.getInstance();
    Project project = null;
    try {
      DevcathlonConfiguration config = manager.getConfiguration();
      String host = config.getHackystat().getSensorbase();
      String password = UserManager.getInstance().getUser(owner).getPassword();
      SensorBaseClient client = new SensorBaseClient(host, owner, password);
      project = client.getProject(owner, name);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    return project;
  }
}
